package com.mxpio.erp.purchase.controller;

import java.io.UnsupportedEncodingException;
import java.util.*;
import java.util.stream.Collectors;

import com.mxpio.erp.common.ItemGroupUtil;
import com.mxpio.erp.common.enums.OrderStatusEnums;
import com.mxpio.erp.common.jpa.model.OrderLine;
import com.mxpio.erp.common.purchase.entity.*;
import com.mxpio.erp.common.purchase.service.VPurchaseOrderLineExecDetailService;
import com.mxpio.erp.common.quality.entity.InQualityOrder;
import com.mxpio.erp.common.quality.entity.InQualityOrderLine;
import com.mxpio.erp.common.technology.entity.*;
import com.mxpio.erp.common.technology.service.ItemGroupService;
import com.mxpio.erp.common.technology.vo.ItemWithSubExtendsVO;
import com.mxpioframework.common.util.BeanReflectionUtils;
import com.mxpioframework.jpa.JpaUtil;
import com.mxpioframework.jpa.query.*;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.mxpio.erp.common.enums.OrderEnums;
import com.mxpio.erp.common.jpa.model.OrderLineKey;
import com.mxpio.erp.common.order.service.OrderLineService;
import com.mxpio.erp.common.purchase.service.PurchaseOrderLineService;
import com.mxpio.erp.common.vo.NoticeClassVo;
import com.mxpioframework.common.vo.Result;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;

@Tag(name = "PurchaseOrderLineController", description = "采购订单行数据接口")
@RestController
@RequestMapping("/erp/purc/poline/")
public class PurchaseOrderLineController {

    @Autowired
    private PurchaseOrderLineService purchaseOrderLineService;

    @Autowired
    private OrderLineService orderLineService;

    @Autowired
    private ItemGroupService itemGroupsSerivce;

    @Autowired
    private VPurchaseOrderLineExecDetailService vPurchaseOrderLineExecDetailService;
    @GetMapping("list")
    @Operation(summary = "采购订单行列表", description = "获取采购订单行列表（无分页）", method = "GET")
    public Result<List<PurchaseOrderLine>> list(@Parameter(description="查询参数") Criteria criteria) throws UnsupportedEncodingException {
        List<PurchaseOrderLine> purchaseOrderLines = purchaseOrderLineService.list(PurchaseOrderLine.class, criteria);
        return Result.OK(purchaseOrderLines);
    }

    @GetMapping("page")
    @Operation(summary = "采购订单行列表", description = "获取采购订单行列表（分页）", method = "GET")
    @Transactional(readOnly = true)
    public Result<Page<PurchaseOrderLine>> page(@Parameter(description="查询参数") Criteria criteria, @Parameter(description="每页条数")Integer pageSize, @Parameter(description="页号")Integer pageNo) throws UnsupportedEncodingException {
        Pageable page = PageRequest.of(pageNo-1, pageSize);
        Criteria subCriteria = Criteria.create();
        List< Object> subCriterions = new ArrayList<>();
        List<String> groupCodes = new ArrayList<>();
        if (criteria.getOrders()!=null&&!criteria.getOrders().isEmpty()){
            subCriteria.setOrders(criteria.getOrders());
        }else{
            subCriteria.addOrder(new Order("createTime",true));//按创建时间降序排列
        }
        if (criteria.getCriterions()!=null&&!criteria.getCriterions().isEmpty()){
            List<Object> criterions = criteria.getCriterions();
            Iterator<Object> iterator = criterions.iterator();
            while (iterator.hasNext()){
                Object next = iterator.next();
                if (next instanceof SimpleCriterion){
                    String fieldName = ((SimpleCriterion) next).getFieldName();
                    if ("itemCode".equals(fieldName)){
                        iterator.remove();
                        subCriterions.add(next);
                    }
                    if ("itemName".equals(fieldName)){
                        iterator.remove();
                        subCriterions.add(next);
                    }
                    if ("drawingNo".equals(fieldName)){
                        iterator.remove();
                        subCriterions.add(next);
                    }
                    if (StringUtils.equals(fieldName,"itemGroupCode")){
                        iterator.remove();
                        String value = ((SimpleCriterion)next).getValue().toString();
                        Criteria c = Criteria.create();
                        List<ItemGroup> itemGroups = itemGroupsSerivce.tree(ItemGroup.class, c);
                        if (itemGroups.size()>0){
                            ItemGroup itemGroupFromList = ItemGroupUtil.getItemGroupFromList(itemGroups, value);
                            ItemGroupUtil.getAllGroupCodeFromItemGroup(groupCodes,itemGroupFromList);
                        }
                    }
                }else if (next instanceof Junction) {//特殊处理，配置过滤服务时，存在一个空or条件，导致会查询所有的主单，影响查询效率
                    List<Object> ju = ((Junction) next).getCriterions();
                    if (ju.isEmpty()){
                        iterator.remove();
                    }
                }
            }
            if (!subCriterions.isEmpty()){
                subCriteria.setCriterions(subCriterions);
            }
            criteria.setOrders(new ArrayList<Order>());//清空，防止主表查询报错
            if (!criteria.getCriterions().isEmpty()){
                List<PurchaseOrder> list = JpaUtil.linq(PurchaseOrder.class).where(criteria).list();
                if (list.size()>0){
                    Set<String> bizNos = list.stream().map(PurchaseOrder::getBizNo).collect(Collectors.toSet());
                    subCriteria.addCriterion("bizNo",Operator.IN,bizNos);
                }else{
                    if (criteria.getCriterions().size()>0){
                        subCriteria.addCriterion("bizNo",Operator.EQ,"-1");
                    }
                }
            }
            if (groupCodes.size()>0){
                subCriteria.addCriterion("itemGroupCode",Operator.IN,groupCodes);//拼接物料组(及子孙节点)过滤条件
            }
        }
        Page<PurchaseOrderLine> purchaseOrderLines = purchaseOrderLineService.listPage(page, subCriteria);
        List<PurchaseOrderLine> contents = purchaseOrderLines.getContent();
        if(contents.size()>0){
            NoticeClassVo receivingNoticeClazz = new NoticeClassVo(ReceivingNotice.class, ReceivingNoticeLine.class);
            NoticeClassVo rejectNoticeClazz = new NoticeClassVo(RejectNotice.class, RejectNoticeLine.class);
            NoticeClassVo inQualityOrderClazz = new NoticeClassVo(InQualityOrder.class, InQualityOrderLine.class);//增加入库验收单 数据统计
            List<NoticeClassVo> noticeClassVos = new ArrayList<>();
            noticeClassVos.add(receivingNoticeClazz);
            noticeClassVos.add(rejectNoticeClazz);
            noticeClassVos.add(inQualityOrderClazz);
            orderLineService.handleBizOrderLineQuantity(contents, noticeClassVos, OrderEnums.AccessType.IN.getCode());


            Set<String> itemCodes = contents.stream().map(PurchaseOrderLine::getItemCode).collect(Collectors.toSet());

            List<Item> items =  JpaUtil.linq(Item.class).in("itemCode", itemCodes).list();
            Map<String, Item> itemMap = JpaUtil.index(items,"itemCode");

            List<ItemLeadTimeProp> leadTimeProps =  JpaUtil.linq(ItemLeadTimeProp.class).equal("propType", "item").in("code", itemCodes).list();
            Map<String, ItemLeadTimeProp> leadTimePropMap = JpaUtil.index(leadTimeProps,"code");

            List<ItemPlanProp> planProps =  JpaUtil.linq(ItemPlanProp.class).equal("propType", "item").in("code", itemCodes).list();
            Map<String, ItemPlanProp> planPropMap = JpaUtil.index(planProps,"code");

            List<ItemPurchaseProp> purchaseProps =  JpaUtil.linq(ItemPurchaseProp.class).equal("propType", "item").in("code", itemCodes).list();
            Map<String, ItemPurchaseProp> purchasePropMap = JpaUtil.index(purchaseProps,"code");

            List<ItemStoreProp> storeProps =  JpaUtil.linq(ItemStoreProp.class).equal("propType", "item").in("code", itemCodes).list();
            Map<String, ItemStoreProp> storePropMap = JpaUtil.index(storeProps,"code");

            List<ItemMaterialProp> materialProps =  JpaUtil.linq(ItemMaterialProp.class).equal("propType", "item").in("code", itemCodes).list();
            Map<String, ItemMaterialProp> materialPropMap = JpaUtil.index(materialProps,"code");
            for (PurchaseOrderLine orderLine:contents){
                String itemCode = orderLine.getItemCode();

                Item item = itemMap.get(itemCode);
                if (item!=null){
                    ItemWithSubExtendsVO extendsVO = new ItemWithSubExtendsVO();
                    BeanReflectionUtils.copyProperties(extendsVO, item);
                    extendsVO.setItemLeadTimeProp(leadTimePropMap.get(itemCode));
                    extendsVO.setItemPlanProp(planPropMap.get(itemCode));
                    extendsVO.setItemPurchaseProp(purchasePropMap.get(itemCode));
                    extendsVO.setItemStoreProp(storePropMap.get(itemCode));
                    extendsVO.setItemMaterialProp(materialPropMap.get(itemCode));
                    orderLine.setItem(extendsVO);
                }
            }
        }

        return Result.OK(purchaseOrderLines);
    }

    @GetMapping("list/{bizNo}")
    @Operation(summary = "根据bizNo获取采购订单行", description = "根据bizNo获取采购订单行", method = "GET")
    @Transactional(readOnly = true)
    public Result<List<PurchaseOrderLine>> getByBizNo(@Parameter(description="业务单号") @PathVariable(name = "bizNo", required = true) String bizNo) {
        Criteria c = Criteria.create().addCriterion("bizNo", Operator.EQ, bizNo);
        List<PurchaseOrderLine> purchaseOrderLines = purchaseOrderLineService.list(PurchaseOrderLine.class, c);
        //处理订单行明细增加物料信息
        /*if (purchaseOrderLines.size()>0){
            List<String> itemCodes = purchaseOrderLines.stream().map(PurchaseOrderLine::getItemCode).collect(Collectors.toList());

            List<Item> items =  JpaUtil.linq(Item.class).in("itemCode", itemCodes).list();
            Map<String, Item> itemMap = JpaUtil.index(items,"itemCode");

            List<ItemLeadTimeProp> leadTimeProps =  JpaUtil.linq(ItemLeadTimeProp.class).equal("propType", "item").in("code", itemCodes).list();
            Map<String, ItemLeadTimeProp> leadTimePropMap = JpaUtil.index(leadTimeProps,"code");

            List<ItemPlanProp> planProps =  JpaUtil.linq(ItemPlanProp.class).equal("propType", "item").in("code", itemCodes).list();
            Map<String, ItemPlanProp> planPropMap = JpaUtil.index(planProps,"code");

            List<ItemPurchaseProp> purchaseProps =  JpaUtil.linq(ItemPurchaseProp.class).equal("propType", "item").in("code", itemCodes).list();
            Map<String, ItemPurchaseProp> purchasePropMap = JpaUtil.index(purchaseProps,"code");

            List<ItemStoreProp> storeProps =  JpaUtil.linq(ItemStoreProp.class).equal("propType", "item").in("code", itemCodes).list();
            Map<String, ItemStoreProp> storePropMap = JpaUtil.index(storeProps,"code");

            List<ItemMaterialProp> materialProps =  JpaUtil.linq(ItemMaterialProp.class).equal("propType", "item").in("code", itemCodes).list();
            Map<String, ItemMaterialProp> materialPropMap = JpaUtil.index(materialProps,"code");
            for (PurchaseOrderLine orderLine:purchaseOrderLines){
                String itemCode = orderLine.getItemCode();

                Item item = itemMap.get(itemCode);
                ItemWithSubExtendsVO extendsVO = new ItemWithSubExtendsVO();
                BeanReflectionUtils.copyProperties(extendsVO, item);
                extendsVO.setItemLeadTimeProp(leadTimePropMap.get(itemCode));
                extendsVO.setItemPlanProp(planPropMap.get(itemCode));
                extendsVO.setItemPurchaseProp(purchasePropMap.get(itemCode));
                extendsVO.setItemStoreProp(storePropMap.get(itemCode));
                extendsVO.setItemMaterialProp(materialPropMap.get(itemCode));
                orderLine.setItem(extendsVO);//
            }
        }*/
        return Result.OK(purchaseOrderLines);
    }


    @GetMapping("list/{bizNo}/{lineNo}")
    @Operation(summary = "根据ID获取采购订单行", description = "根据ID获取采购订单行", method = "GET")
    public Result<PurchaseOrderLine> getById(@Parameter(description="业务单号") @PathVariable(name = "bizNo", required = true) String bizNo, @Parameter(description="行号") @PathVariable(name = "lineNo", required = true)String lineNo) {
        OrderLineKey lineKey = new OrderLineKey();
        lineKey.setLineNo(lineNo);
        lineKey.setBizNo(bizNo);
        PurchaseOrderLine purchaseOrderLine = purchaseOrderLineService.getById(PurchaseOrderLine.class, lineKey);
        return Result.OK(purchaseOrderLine);
    }

    @PostMapping("add")
    @Operation(summary = "新增采购订单行", description = "新增采购订单行", method = "POST")
    public Result<PurchaseOrderLine> add(@RequestBody PurchaseOrderLine purchaseOrderLine) {
        purchaseOrderLineService.save(purchaseOrderLine);
        return Result.OK(purchaseOrderLine);
    }

    @PutMapping("edit")
    @Operation(summary = "编辑采购订单行", description = "编辑采购订单行", method = "PUT")
    public Result<PurchaseOrderLine> edit(@RequestBody PurchaseOrderLine purchaseOrderLine) {
        purchaseOrderLineService.update(purchaseOrderLine);
        return Result.OK(purchaseOrderLine);
    }

    @DeleteMapping("remove/{ids}")
    @Operation(summary = "根据id删除采购订单行", description = "删除采购订单行,多个id用英文逗号分隔,bizNo和lineNo间使用英文冒号分隔,bizNo在前,lineNo在后", method = "DELETE")
    public Result<PurchaseOrderLine> remove(@PathVariable(name = "ids", required = true) String ids) {
        String[] id = ids.split(",");
        for(String key : id){
            String[] pk = key.split(":");
            OrderLineKey lineKey = new OrderLineKey();
            lineKey.setBizNo(pk[0]);
            lineKey.setLineNo(pk[1]);
            purchaseOrderLineService.remove(PurchaseOrderLine.class, lineKey);
        }
        return Result.OK();
    }

    @PutMapping("open/{ids}")
    @Operation(summary = "打开采购订单行", description = "打开采购订单行,多个id用英文逗号分隔,bizNo和lineNo间使用英文冒号分隔,bizNo在前,lineNo在后", method = "PUT")
    public Result<? extends OrderLine> open(@PathVariable(name = "ids", required = true) String ids) {
        return orderLineService.updateCloseStatus(PurchaseOrderLine.class, ids, OrderStatusEnums.CloseStatus.OPEN);
    }

    @PutMapping("close/{ids}")
    @Operation(summary = "关闭采购订单行", description = "关闭采购订单行", method = "PUT")
    public Result<? extends OrderLine> close(@Parameter(description="业务单号，多个id用英文逗号分隔,bizNo和lineNo间使用英文冒号分隔,bizNo在前,lineNo在后") @PathVariable(name = "ids", required = true) String ids) {
        return orderLineService.updateCloseStatus(PurchaseOrderLine.class, ids, OrderStatusEnums.CloseStatus.CLOSED);
    }

    @GetMapping("vlist")
    @Operation(summary = "采购订单明细执行详情视图", description = "采购订单明细执行详情视图", method = "GET")
    public Result<List<VPurchaseOrderLineExecDetail>> vlist(Criteria criteria) throws UnsupportedEncodingException {
        List<VPurchaseOrderLineExecDetail> list = vPurchaseOrderLineExecDetailService.list(criteria);
        return Result.OK(list);
    }

    @GetMapping("vpage")
    @Operation(summary = "采购订单明细执行详情视图 分页", description = "采购订单明细执行详情视图 分页", method = "GET")
    public Result<Page<VPurchaseOrderLineExecDetail>> vpage(Criteria criteria, Integer pageSize, Integer pageNo) throws UnsupportedEncodingException {
        Pageable pageAble = PageRequest.of(pageNo-1, pageSize);
        Page<VPurchaseOrderLineExecDetail> page = vPurchaseOrderLineExecDetailService.listPage(pageAble, criteria);
        return Result.OK(page);
    }
}
